import 'dart:core';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:ivy_baby_record/user/colors/colors.dart';
import 'package:ivy_baby_record/user/constants/constants.dart';
import 'package:ivy_baby_record/user/model/record/has_record.dart';
import 'package:ivy_baby_record/user/model/record/weekday_info.dart';
import 'package:ivy_baby_record/user/pages/record/record_home.dart';
import 'package:ivy_baby_record/user/pages/record/record_notifier.dart';
import 'package:ivy_baby_record/user/util/datetime.dart';
import 'package:ivy_baby_record/user/util/user_util.dart';
import 'package:provider/provider.dart';

class WeeklyCalendar extends StatefulWidget {
  final int minDateTime;
  final int maxDateTime;
  final int curDateTime;
  final DateTime min;
  final DateTime max;
  final DateTime cur;
  final DateSwitchCallback callback;

  WeeklyCalendar(
      {this.minDateTime = 0,
      this.maxDateTime = 0,
      this.curDateTime = 0,
      required this.min,
      required this.max,
      required this.cur,
      required this.callback});

  @override
  State<StatefulWidget> createState() => _WeeklyCalendarState();
}

class _WeeklyCalendarState extends State<WeeklyCalendar> {
  late PageController _pageController;
  int _currentPage = 0;

  late DateTime _curWeekStart;
  late DateTime _curWeekEnd;
  late int _weeks;
  late int _dayIndex;
  late List<WeekdayInfo?> _list;

  @override
  void initState() {
    super.initState();
    _pageController = PageController();
    _pageController.addListener(() {
      var offset = _pageController.offset;
      var page = _pageController.page;
    });
    locateCurTime();
  }

  void locateCurTime() {
    DateTime cur = DateTimeUtil.getStartDateTime(
        widget.cur ?? DateTime.fromMillisecondsSinceEpoch(widget.curDateTime));
    DateTime min = DateTimeUtil.getStartDateTime(
        widget.min ?? DateTime.fromMillisecondsSinceEpoch(widget.minDateTime));
    DateTime max = DateTimeUtil.getStartDateTime(
        widget.max ?? DateTime.fromMillisecondsSinceEpoch(widget.maxDateTime));

    int weekdayIndex = cur.weekday % 7;
    _curWeekStart = cur.subtract(Duration(days: weekdayIndex));
    _curWeekEnd = cur.add(Duration(days: 7 - (weekdayIndex + 1)));

    var startDiffDays = _curWeekStart.difference(min).inDays.abs();
    var weeksBeforeCurWeek =
        startDiffDays ~/ 7 + (startDiffDays % 7 == 0 ? 0 : 1);
    var endDiffDays = _curWeekEnd.difference(max).inDays.abs();
    var weeksAfterCurWeek = endDiffDays ~/ 7 + (endDiffDays % 7 == 0 ? 0 : 1);
    _weeks = 1 + weeksBeforeCurWeek + weeksAfterCurWeek;

    _list = List.filled(_weeks, null);
    WeekdayInfo curWeekdayInfo = WeekdayInfo(_curWeekStart, _curWeekEnd);
    _list[weeksBeforeCurWeek] = curWeekdayInfo;

    var lastWeekEnd = _curWeekStart.subtract(Duration(days: 1));
    var lastWeekStart = lastWeekEnd.subtract(Duration(days: 7 - 1));

    for (var i = weeksBeforeCurWeek - 1; i >= 0; --i) {
      WeekdayInfo weekdayInfo = WeekdayInfo(lastWeekStart, lastWeekEnd);
      _list[i] = weekdayInfo;
      lastWeekEnd = lastWeekStart.subtract(Duration(days: 1));
      lastWeekStart = lastWeekEnd.subtract(Duration(days: 7 - 1));
    }

    lastWeekStart = _curWeekEnd.add(Duration(days: 1));
    for (var i = weeksBeforeCurWeek + 1; i < _weeks; ++i) {
      lastWeekEnd = lastWeekStart.add(Duration(days: 7 - 1));
      WeekdayInfo weekdayInfo = WeekdayInfo(lastWeekStart, lastWeekEnd);
      _list[i] = weekdayInfo;
      lastWeekStart = lastWeekEnd.add(Duration(days: 1));
    }

    _dayIndex = -1;
    int i = 0;
    for (var week in _list) {
      var start = week!.start.subtract(Duration(days: 1));
      var end = week!.end.add(Duration(days: 1));
      if (cur.isBefore(end) && cur.isAfter(start)) {
        for (int j = 0; j < 7; ++j) {
          if (cur.isAtSameMomentAs(week!.start.add(Duration(days: j)))) {
            _dayIndex = i * 7 + j;
            break;
          }
        }
      }
      if (_dayIndex >= 0) {
        break;
      }
      ++i;
    }

    WidgetsBinding.instance.addPostFrameCallback((timestamp) {
      if (_pageController.hasClients) {
        _pageController.jumpToPage(weeksBeforeCurWeek);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: CustomColors.c1,
      height: 66,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          SizedBox(height: 5),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              buildDayNameWidget('日'),
              buildDayNameWidget('一'),
              buildDayNameWidget('二'),
              buildDayNameWidget('三'),
              buildDayNameWidget('四'),
              buildDayNameWidget('五'),
              buildDayNameWidget('六'),
            ],
          ),
          SizedBox(height: 5),
          Container(
            child: Expanded(
              child: SizedBox(
                child: Consumer<RecordNotifier>(
                  builder: (context, notifier, child) {
                    print('calendar date is ${notifier?.selectDate}');
                    locate(notifier);
                    return PageView.builder(
                        onPageChanged: (index) {
                          _currentPage = index;
                        },
                        reverse: false,
                        physics: BouncingScrollPhysics(),
                        scrollDirection: Axis.horizontal,
                        controller: _pageController,
                        itemCount: _weeks,
                        itemBuilder: (context, index) {
                          return buildWeekWidget(context, index);
                        });
                  },
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  void locate(RecordNotifier notifier) {
    int i = 0;
    DateTime cur = notifier.selectDate;
    for (var week in _list) {
      var start = week!.start.subtract(Duration(days: 1));
      var end = week.end.add(Duration(days: 1));
      if (cur.isBefore(end) && cur.isAfter(start)) {
        for (int j = 0; j < 7; ++j) {
          if (cur.isAtSameMomentAs(week.start.add(Duration(days: j)))) {
            if (_currentPage != i) {
              if (_pageController.hasClients) {
                _pageController.jumpToPage(i);
              }
            }
            break;
          }
        }
      }
      ++i;
    }
  }

  Widget buildWeekWidget(BuildContext context, int index) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: buildDayNumWidgets(context, index),
    );
  }

  Widget buildDayNameWidget(String name) =>
      Text(name, style: TextStyle(color: CustomColors.c4, fontSize: 10));

  List<Widget> buildDayNumWidgets(BuildContext context, index) {
    WeekdayInfo info = _list[index]!;
    List<Widget> widgets = List.empty(growable: true);
    DateTime todayStart = DateTimeUtil.getStartDateTime(DateTime.now());
    for (var i = 0; i < 7; ++i) {
      final DateTime start = info.start.add(Duration(days: i));
      int difference = start.difference(todayStart).inDays;
      bool isToday = difference == 0;

      widgets.add(Container(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Container(
              height: 4,
              child: buildIndicators(context, DateTimeUtil.formatYMDDate(start)),
            ),
            SizedBox(height: 1),
            Container(
                width: 32,
                height: 32,
                child: Consumer<RecordNotifier>(
                  builder: (context, notifier, child) {
                    final ButtonStyle flatButtonStyle = TextButton.styleFrom(
                      backgroundColor: DateTimeUtil.isSameDay(start, notifier.selectDate) ? CustomColors.c8 : CustomColors.c1,
                      foregroundColor: DateTimeUtil.isSameDay(start, notifier.selectDate) ? CustomColors.c8 : CustomColors.c1,
                      minimumSize: Size(88, 44),
                      padding: EdgeInsets.all(0),
                      shape: CircleBorder(side: BorderSide.none),
                    );
                    return TextButton(
                      // color: DateTimeUtil.isSameDay(start, notifier.selectDate) ? CustomColors.c8 : CustomColors.c1,
                      // highlightColor: DateTimeUtil.isSameDay(start, notifier.selectDate) ? CustomColors.c8 : CustomColors.c1,
                      style: flatButtonStyle,
                      onPressed: () {
                        notifier.selectDate = start;
                        widget.callback?.call(start);
                      },
                      // shape: CircleBorder(side: BorderSide.none),
                      // padding: EdgeInsets.all(0),
                      child: Text(isToday ? '今日' : start.day.toString(),
                          style: TextStyle(
                            color: DateTimeUtil.isSameDay(start, notifier.selectDate) ? Colors.white : CustomColors.c4,
                            fontSize: isToday ? 14 : 18,
                            fontWeight: FontWeight.normal,
                          )),
                    );
                  },
                )
            )
          ],
        ),
      ));
    }
    return widgets;
  }

  Widget buildIndicators(BuildContext context, String date) {
    return Consumer<RecordNotifier>(
      builder: (context, notifier, child) {
        return Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: buildIndicatorItems(context, date, notifier),
        );
      },
    );
  }

  List<Widget> buildIndicatorItems(BuildContext context, String date, RecordNotifier notifier) {
    List<Widget> list = [];
    if (notifier.hasRecordMap.isNotEmpty) {
      var hints = [
        Color(0),
        CustomColors.hint_growth,
        CustomColors.hint_record,
        CustomColors.hint_medicine,
        CustomColors.hint_medicine1,
        CustomColors.hint_record,
        Color(0)
      ];
      for (int i = Constants.TYPE_HAS_RECORD_GROW; i <
          Constants.TYPE_HAS_RECORD_OTHER_PREGNANT; ++i) {
        String key = '${UserUtils.childId()}-$date-$i';
        HasRecord? hasRecord = notifier.hasRecordMap[key];
        if (hasRecord?.has == 1) {
          list.add(Container(
            margin: EdgeInsets.symmetric(horizontal: 0.5),
            width: 4,
            height: 4,
            child: Material(
              color: hasRecord!.type >= hints.length ? Color(0) : hints[hasRecord.type],
              shape: CircleBorder(side: BorderSide.none),
            ),
          ));
        }
      }
    }

    return list;
  }
}
